package com.rabbit.aspect;

import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson.JSON;
import com.rabbit.constant.SecurityConstant;
import com.rabbit.dto.RequestDTO;
import com.rabbit.dto.ResponseDTO;
import com.rabbit.handler.RequestContext;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.MDC;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;

/**
 * <h1>日志切面</h1>
 *
 * @author zjw
 * @date 2021/6/28 9:24
 */
@Aspect
@Component
@Order(1)
@Slf4j
public class LogAspect {

    @Pointcut("execution(* com.rabbit.controller..*(..)))")
    public void pointCut() {
    }

    @Around("pointCut() ")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) ra).getRequest();

        List<Object> params = new ArrayList<>();
        for (Object obj : pjp.getArgs()) {
            if (!(obj instanceof ServletRequest || obj instanceof ServletResponse)) {
                params.add(obj);
            }
        }

        RequestDTO requestObj = new RequestDTO();
        requestObj.setRequestUri(request.getRequestURI());
        requestObj.setRequestParams(params);

        String traceId = UUID.fastUUID().toString();
        MDC.put(SecurityConstant.LOG_TRACE_ID, traceId);
        log.info("request: " + JSON.toJSONString(requestObj));
        RequestContext.put(SecurityConstant.LOG_TRACE_ID, traceId);

        Object result = pjp.proceed();
        if (result != null) {
            HttpServletResponse response = ((ServletRequestAttributes) ra).getResponse();
            ResponseDTO<Object> responseDTO = ResponseDTO.builder()
                    .status(response.getStatus())
                    .requestUri(requestObj.getRequestUri())
                    .result(result).build();
            log.info("response: " + JSON.toJSONString(responseDTO));
        }
        return result;
    }

}
